/* 
 * File:   ObjParser.cpp
 * Author: brady
 * 
 * Created on August 27, 2011, 1:31 PM
 */

#include <parsing/ObjParser.h>

ObjParser::ObjParser() {
}

ObjParser::ObjParser(const ObjParser& orig) {
}

ObjParser::~ObjParser() {
}



vector<Vertex*> ObjParser::verts = vector<Vertex*>();
vector<Vector3D> ObjParser::normals = vector<Vector3D>();
vector<Vector3D> ObjParser::textureCoords = vector<Vector3D>();
vector<TriangleMesh*> ObjParser::meshes = vector<TriangleMesh*>();
int ObjParser::meshCount = 0;

TriangleMesh* ObjParser::parseObj(const char* fileName){
    
    fstream in_file;
    in_file.open(fileName);
    if(!in_file.is_open()){
        char dir[FILENAME_MAX];
        getcwd(dir, FILENAME_MAX);
        cout << "Failed to open " << dir <<"/" << fileName << "\n";
        return NULL;
    }

    TriangleMesh *mesh = new TriangleMesh();
    vector<Vector3D> points;
    vector<Vector3D> normals;
    vector<Vector3D> textures;
    int fcount = 0;
    int vcount = 0;
    int ncount = 0;
    int tcount = 0;
    while (!in_file.eof()) {
        
        string line = "";
        getline(in_file, line);
        
        if(line.empty()) continue;
        
        if(line.at(0) == '#') continue;
        
        string bite="";
        stringstream lstream;
        lstream << line;
        lstream >> bite;
        
        if(bite == "v"){
            //vertex
            double x, y, z;
            lstream >> x >> y >> z;
            points.push_back(Vector3D(x,y,z));
            vcount++;
        }
        else if(bite == "vn"){
            //normal
            double u, v, w;
            lstream >> u >> v >> w;
            normals.push_back(Vector3D(u,v,w));
            ncount++;
        }
        else if(bite == "vt"){
            //texture coord
            double x, y, z;
            lstream >> x >> y >> z;
            textures.push_back(Vector3D(x,y,z));
            tcount++;
        }
        else if(bite == "f"){
            //face 
            //f v/vt/vn v/vt/vn v/vt/vn v/vt/vn
            
            Vertex *v1 = NULL;
            Vertex *v2 = NULL;
            Vertex *v3 = NULL;
            Vertex *v4 = NULL;
            
            if(lstream.peek() == ' '){
                lstream.get();            
            }
            string data;
            int idx = 0;
            while(!lstream.eof()){ 
                Vertex* v;                
                v = new Vertex();
                
                stringstream vertstream;
                string vertData;
                getline(lstream, vertData, ' ');
                vertstream << vertData;
                string data;
                getline(vertstream, data, '/');
                v->location = points[atoi(data.c_str())-1];
                data="";
                getline(vertstream, data, '/');
                int txi = atoi(data.c_str()) - 1;
                if(txi > 0){
                    v->hasTexture = true;
                    v->textureMap = textures[txi];
                }
                data="";
                getline(vertstream, data);
                int ni = atoi(data.c_str()) -1;
                if(ni > 0){
                    v->hasNormal = true;
                    v->normal = normals[ni];
                }
                
                if(idx == 0) v1 = v;
                if(idx == 1) v2 = v;
                if(idx == 2) v3 = v;
                if(idx == 3) v4 = v;
                
                
                idx++;
            }
            
            //add the triangle
            mesh->addTriangle(v1, v2, v3);  
            if(v4 != NULL){
                mesh->addTriangle(v1, v3, v4);
            }
        }
        else continue;   
    }
    //don't finalize yet. needs a shader
    return mesh;
}

vector<TriangleMesh*> ObjParser::parseObj2(const char* fileName){
    verts = vector<Vertex*>();
    obj::obj_parser parser;
    parser.geometric_vertex_callback(ObjParser::geometric_vertex_callback);
    parser.parse(fileName);

}

void ObjParser::material_name_callback(std::string mtlName){
    meshCount++;
}

void ObjParser::geometric_vertex_callback(obj::float_type x, obj::float_type y, obj::float_type z){
    verts.push_back(new Vertex(Vector3D(x, y, z) ) );
}

void ObjParser::vertex_normal_callback(float_type x, float_type y, float_type z){
    normals.push_back(Vector3D(x, y, z));
}

void ObjParser::texture_coord_callback(float_type x, float_type y) {
    textureCoords.push_back(Vector3D(x, y, 0.0));
}

void ObjParser::triangle_face_vertices_callback(index_type v1, index_type v2, index_type v3) {
    //if we haven't named a material, assume only 1 object
    if(meshCount == 0){
        meshCount++;
    }
    while(meshes.size() < meshCount){
        meshes.push_back(new TriangleMesh());
    }

}

void ObjParser::triangle_face_vertices_normals_callback(index_2_tuple_type v1, index_2_tuple_type v2, index_2_tuple_type v3) {
}

void ObjParser::triangle_face_vertices_textureCoords_callback(index_2_tuple_type v1, index_2_tuple_type v2, index_2_tuple_type v3) {
}

void ObjParser::triangle_face_vertices_textureCoords_normals_callback(index_3_tuple_type v1, index_3_tuple_type v2, index_3_tuple_type v3) {
}

void ObjParser::quad_face_vertices_callback(index_type v1, index_type v2, index_type v3, index_type v4) {
}

void ObjParser::quad_face_vertices_normals_callback(index_2_tuple_type v1, index_2_tuple_type v2, index_2_tuple_type v3, index_2_tuple_type v4) {
}

void ObjParser::quad_face_vertices_textureCoords_callback(index_2_tuple_type v1, index_2_tuple_type v2, index_2_tuple_type v3, index_2_tuple_type v4) {
}

void ObjParser::quad_face_vertices_textureCoords_normals_callback(index_3_tuple_type v1, index_3_tuple_type v2, index_3_tuple_type v3, index_3_tuple_type v4) {
}

void ObjParser::cleanup(){
    
}

